/********************************************************
* @file: GenExactCurve.cpp (v3.80)
* @date: 22/03/2012
* @author: Ricardo C. Marques
**********************************************************/

// Standard Libraries
#include <stdlib.h>

// Module Own Header File
#include "GenExactCurve.hpp" 

// Test Header File
#include "TestExcCrv.h"

// Auxiliary Header Files
#if 0 // mtool3d
#include "../geommodel/geometry/mgCurve.h"
#include "../geommodel/geometry/mgVertex.h"
#include "../gra/mgPick.h"
#endif
// GenExactCurve Methods
////////////////////////////////////////////////////////////////////
GenExactCurve::GenExactCurve()
{
    // Initializes Tolerance
  //  mgPick pick;
  m_tolerance = 0.0001;  // tolerance must be set correctly

  // Initializes Curves data
  m_CurveArraySize = 0;  
  m_CurveArrayIndex = 0;  
  m_CurvePointsArray = NULL;

  // Initializes Multiple Curve Management Data
  m_CurvesNumber = 0;
  m_MaxCurves = 0;
  m_CurvesSizesArray = NULL;
  m_InvCrvStartIdxArray = NULL;
  m_PreviousCurveEndIndex = 0;

#if PRINT_FILE
    m_output = fopen("output.txt", "wt");
    if(m_output==NULL)
        printf("Nao foi impossivel criar arquivo de saida\n");
#endif

}
////////////////////////////////////////////////////////////////////
GenExactCurve::~GenExactCurve()
{
#if PRINT_FILE
    if(m_output!=NULL)
        fclose(m_output);
#endif

}
////////////////////////////////////////////////////////////////////
size_t 
GenExactCurve::getNumberOfCurves()
// Returns the number of curves created
{
  return m_MaxCurves;
}
////////////////////////////////////////////////////////////////////
size_t 
GenExactCurve::getCurveSize()
// Returns the number of points of the current curve
{
  return m_CurvesSizesArray[m_CurvesNumber];
}
////////////////////////////////////////////////////////////////////
Point3D*
GenExactCurve::getFrstCurve()
// Returns a pointer to the first curve
{
  // Sets the returned curve as the first
  // and return the first curve
  m_CurvesNumber=1;
#if SHOW_CURVE_POINTS
  printf("\n\n");
  for(size_t i=0; i<getCurveSize(); i++)
    printf(  "CurvePointsArray[%d][%d]={%.6lf, %.6lf, %.6lf}\n", 
    m_CurvesNumber, i,   
    m_CurvePointsArray[i].getX(), 
    m_CurvePointsArray[i].getY(),
    m_CurvePointsArray[i].getZ()    );
#endif
#if PRINT_FILE
    fprintf(m_output, "Curve 1\n");
    for(size_t i=0; i<getCurveSize(); i++)
        fprintf(m_output, "%.10lf %.10lf %.10lf\n",    
        m_CurvePointsArray[i].getX(), 
        m_CurvePointsArray[i].getY(),
        m_CurvePointsArray[i].getZ()    );
#endif
    if(getCurveSize()<=0)
        return NULL;

  return m_CurvePointsArray;
}
////////////////////////////////////////////////////////////////////
Point3D* 
GenExactCurve::getNextCurve()
// Returns pointer to the next curve or NULL
{
  // Checks if there is a next
  // curve to be returned
  if(m_CurvesNumber>=m_MaxCurves)
    return NULL;

  // Calculates the start position of the
  // next curve in CurvePointsArray
  size_t sum=0;
  for(size_t i=1; i<=m_CurvesNumber; i++)
    sum+=m_CurvesSizesArray[i];

  // Checks if the calculated position
  // is not outside CurvePointsArray
  if(sum>=m_CurveArraySize)
    return NULL;

  // Updates the next curve index
  m_CurvesNumber++;

#if SHOW_CURVE_POINTS
  for(size_t i=sum; i<sum+getCurveSize(); i++)
    printf(  "CurvePointsArray[%d][%d]={%.6lf, %.6lf, %.6lf}\n", 
    m_CurvesNumber, i,   
    m_CurvePointsArray[i].getX(), 
    m_CurvePointsArray[i].getY(),
    m_CurvePointsArray[i].getZ()    );
#endif
#if PRINT_FILE
    fprintf(m_output, "Curve %d\n", m_CurvesNumber);
    for(size_t i=sum; i<sum+getCurveSize(); i++)
        fprintf(m_output, "%.10lf %.10lf %.10lf\n", 
        m_CurvePointsArray[i].getX(), 
        m_CurvePointsArray[i].getY(),
        m_CurvePointsArray[i].getZ()    );
#endif

  // Return the curve
  return &m_CurvePointsArray[sum];
}
////////////////////////////////////////////////////////////////////
void
GenExactCurve::KillCurves()
// Frees the array with coords of 
// all curve(s) on surface points
// and array for multiple curves
// management
{    
    m_CurveArraySize=0;
    m_CurveArrayIndex=0;
    m_PreviousCurveEndIndex=0;
    if(m_CurvePointsArray!=NULL)
  {
      free(m_CurvePointsArray);
    m_CurvePointsArray=NULL;
  }

    m_CurvesNumber=0;
    m_MaxCurves=0;
    if(m_CurvesSizesArray!=NULL)
  {
      free(m_CurvesSizesArray);
    m_CurvesSizesArray=NULL;
  }

  if(m_InvCrvStartIdxArray!=NULL)
  {
    free(m_InvCrvStartIdxArray);
    m_InvCrvStartIdxArray=NULL;
  }
}

////////////////////////////////////////////////////////////////////
void
GenExactCurve::InsertCurvePoint( double _Point[3] )
// Inserts the given point into CurvePointsArray, 
// increasing CurveArray if necessary. This method
// does not check if the current curve already 
// contains the given point.
{
  // Checks if Curve Array is not full
  if( m_CurveArrayIndex+1 >= m_CurveArraySize )
  {
    // Doubles Curve Array Size
    m_CurveArraySize +=  m_CurveArraySize;

    // Reallocates Curve Array
    m_CurvePointsArray = (Point3D*) realloc( 
      m_CurvePointsArray, 
      m_CurveArraySize*sizeof(Point3D)    );

  }

  // Insert Point into Curve Array 
  m_CurvePointsArray[m_CurveArrayIndex] =
    Point3D(  _Point[0], _Point[1], _Point[2] );

#if SHOW_CURVE_CREATION
  printf(  "CurvePointsArray[%d][%d]={%.6lf, %.6lf, %.6lf}", 
    m_CurvesNumber, m_CurveArrayIndex,  
    _Point[0], _Point[1], _Point[2]              );
#if !SHOW_SEARCH
  printf("\n");
#endif
#if SHOW_PAUSED
  getchar(); // A pause
#endif
#endif

  // Update Curve Arrays Index
  m_CurveArrayIndex++;

}
////////////////////////////////////////////////////////////////////
void 
GenExactCurve::AddCurvePoint( double _Point[3] )
// Adds the given point into CurvePointsArray
// unless the current curve already contains 
// this point.
{
  // Avoids a Point repetition in the curve being built
    // Checks repetition only if there is more than 1 point
  if(m_CurveArrayIndex>=1)
    {
      size_t start = 0;
      for(size_t j=0; j<m_CurvesNumber; j++)
        start +=m_CurvesSizesArray[j];
      for(size_t i=start; i<=m_CurveArrayIndex-1; i++)
      {
        if( m_CurvePointsArray[i].distance( 
            Point3D(_Point[0], _Point[1], _Point[2]) ) 
          <= m_tolerance              )
          return;
      }
    }

  // Inserts the given point 
  // in the current curve
  InsertCurvePoint(_Point);

}
////////////////////////////////////////////////////////////////////
void 
GenExactCurve::CreateFirstCurve()
// Allocates CurvePointsArray and CurveSizesArray
// and initializes its indexes and sizes
{
  // Allocates CurvePointsArray and 
  // initializes its index and size
  m_CurveArraySize = 200;
  m_CurvePointsArray = 
    (Point3D*) malloc(m_CurveArraySize*sizeof(Point3D));
  m_CurveArrayIndex=0;

  // Allocates CurveSizesArray
  // (needed to manage multiple curves)
  m_CurvesNumber = 1;
  m_MaxCurves = 3;
  m_CurvesSizesArray = 
    (size_t*)malloc(m_MaxCurves*sizeof(size_t));
  m_CurvesSizesArray[0]=0;
  m_InvCrvStartIdxArray = 
    (int*)malloc(m_MaxCurves*sizeof(int));
  m_InvCrvStartIdxArray[0]=-1;
  m_InvCrvStartIdxArray[1]=-1; // First Curve is not inverted
  m_PreviousCurveEndIndex=0;
}
////////////////////////////////////////////////////////////////////
void
GenExactCurve::CreateNewCurve(bool IsInverted)
// Sets the end of the previous curve and
// get ready for a new one
{
  // Avoids creating a Curve with 0 points
  if(m_PreviousCurveEndIndex==m_CurveArrayIndex)
  {
#if SHOW_CURVE_CREATION
    printf("Attempt to create a curve with 0 points was aborted!\n");
#endif
    return;  
  }

    // Corrects curve with 1 point
    if(m_PreviousCurveEndIndex+1==m_CurveArrayIndex)
  {
#if SHOW_CURVE_CREATION
    printf("Attempt to create a curve with 1 point! Curve was corrected!\n");
#endif
        m_CurvesSizesArray[--m_CurvesNumber]++;
  }

  m_PreviousCurveEndIndex=m_CurveArrayIndex;

  // If the previous segment was inverted, the
  // new curve is still inverted
  if(m_InvCrvStartIdxArray[m_CurvesNumber]!=-1)
  {
        IsInverted=true;
  }

#if SHOW_CURVE_CREATION
  if(IsInverted)
    printf("The next curve is inverted!\n");
#endif

  // Checks if CurvesSizesArray is not full
  if(m_CurvesNumber+1>m_MaxCurves)
  {
    // Double Maximum number of Curves
    m_MaxCurves +=  m_MaxCurves;

    // Reallocates CurvesSizesArray
    m_CurvesSizesArray = 
      (size_t*) realloc( m_CurvesSizesArray, 
      m_MaxCurves*sizeof(size_t)    );
    if(IsInverted)
      m_InvCrvStartIdxArray = 
        (int*) realloc( m_InvCrvStartIdxArray, 
        m_MaxCurves*sizeof(int)    );

  }

  // Update the size of the current curve 
    if(m_CurvesNumber>0)
    {
        size_t sum=0;
        for(size_t i=m_CurvesNumber-1; i>0; i--)
            sum+=m_CurvesSizesArray[i];
        m_CurvesSizesArray[m_CurvesNumber] = m_CurveArrayIndex-sum;
    }    
  
  if(IsInverted)
    // Set curve as inverted with start index at 
    // CurveArrayIndex and update the number of curves
    m_InvCrvStartIdxArray[m_CurvesNumber++] = (int)m_CurveArrayIndex; 
  else
    // Set new curve as not inverted and
    // update the number of curves
    m_InvCrvStartIdxArray[m_CurvesNumber++] = -1; 

}
////////////////////////////////////////////////////////////////////
void
GenExactCurve::CloseCurrentCurve()
// Adds the first point of the current curve
// as the last point of this curve. Besides
// closing the current curve, splits it in
// two curves. Points added after this method
// has been called will belong to a new curve.
// So, there is not necessary to call 
// CreateNewCurve after CloseCurrentCurve.
{    
    // Get position were current curve
    // starts and ends in CurvePointsArray
    if(m_CurveArrayIndex==0)
        return;
    size_t start = 0;
    for(size_t j=0; j<m_CurvesNumber; j++)
        start +=m_CurvesSizesArray[j];
    size_t end = m_CurveArrayIndex-1;
    size_t half = start + (end-start)/2;

    // Checks if Curve Array is not full
    // (get space for adding two new points)
    if( m_CurveArrayIndex+2 >= m_CurveArraySize )
    {
        // Doubles Curve Array Size
        m_CurveArraySize +=  m_CurveArraySize;

        // Reallocates Curve Array
        m_CurvePointsArray = (Point3D*) realloc( 
            m_CurvePointsArray, 
            m_CurveArraySize*sizeof(Point3D)    );
    }

    // Add current curve first point in the last
    // position of CurvePointsArray.
    double Point[3];
    m_CurvePointsArray[start].getXYZ(Point);
    m_CurvePointsArray[end+2] =
        Point3D(  Point[0], Point[1], Point[2] );
 
    // Shift every point in the last half of 
    // CurvePointsArray by one position,
    // keeping the half point duplicated.
    for(size_t i=end; i>=half; i--)
    {
        m_CurvePointsArray[i].getXYZ(Point);
        m_CurvePointsArray[i+1] =
            Point3D(  Point[0], Point[1], Point[2] );
    }

#if SHOW_CURVE_CREATION
    printf("The current curve is closed and will be splitted!\n");
#endif

    // Split current curve in two 
    // and update curve sizes
    m_CurveArrayIndex = half+1;
    CreateNewCurve();
    m_CurveArrayIndex = end+3;
    CreateNewCurve();

}
////////////////////////////////////////////////////////////////////
void
GenExactCurve::EndCreatingCurves()
// Sets the end of the previous curve as the last curve
{
    if(m_PreviousCurveEndIndex==m_CurveArrayIndex)
    {
#if SHOW_CURVE_CREATION
    printf("Attempt to create a curve with 0 points was aborted!\n");
#endif
        m_CurvesNumber--;
        if(m_CurvesNumber==0)
        {
            size_t temp = m_CurvesSizesArray[0];
            m_CurvesSizesArray[1]=temp;
            m_CurvesSizesArray[0]=0;
            m_CurvesNumber=1;
        }
    }
    else
    {
        if(m_PreviousCurveEndIndex+1==m_CurveArrayIndex)
      {
#if SHOW_CURVE_CREATION
        printf("Attempt to create a curve with 1 point! Curve was corrected!\n");
#endif
            m_CurvesSizesArray[--m_CurvesNumber]++;
      }

        // Update the Size of CurvePointsArray
        m_CurveArraySize=m_CurveArrayIndex;

      // Checks if CurvesSizesArray is not full
      if(m_CurvesNumber+1>m_MaxCurves)
      {
        // Double Maximum number of Curves
        m_MaxCurves +=  m_MaxCurves;

        // Reallocates CurvesSizesArray
        m_CurvesSizesArray = 
          (size_t*) realloc( m_CurvesSizesArray, 
          m_MaxCurves*sizeof(size_t)    );
      }

      // Update the size of the current curve 
      size_t sum=0;
        if( m_CurvesNumber!=0 )
        {
          for(size_t i=m_CurvesNumber-1; i!=0; i--)
            sum+=m_CurvesSizesArray[i];
          m_CurvesSizesArray[m_CurvesNumber] = m_CurveArrayIndex-sum;
        }
    }

    // Update the Size of CurvePointsArray
    m_CurveArraySize=m_CurveArrayIndex;

    // Update the number of curves
    m_MaxCurves = m_CurvesNumber;

    // Initializes iterator, unless no curve was created
    if(m_CurveArraySize>1)
        m_CurvesNumber=1;
    else
    {
        m_CurvesNumber=0;
        m_CurvesSizesArray[0]=0;
        m_CurvesSizesArray[1]=0;
    }

}
////////////////////////////////////////////////////////////////////
void 
GenExactCurve::FilterCurves()
// Filter small segments and removes zip-zag parts of CurvePointsArray, 
// decreasing the number of points if necessary.
{
    Point3D* currCurve;
    bool found_loop = false;
    bool found_small_seg = false;
    const double smallestSegFactor = 0.01;
    double curveLength = 0.0;
    double smallestSeg = 0.0;

    if(getFrstCurve()==NULL)
        return;

    // Check for at least one curve with loop
    for( currCurve = getFrstCurve();
         found_loop == false && currCurve != NULL;
         currCurve = getNextCurve() )
    {
        found_loop = CheckCurveLoops( getCurveSize(), currCurve,
            &curveLength, &smallestSeg );
        if( smallestSeg/curveLength < smallestSegFactor )
            found_small_seg = true;
    }

    if( !found_loop && !found_small_seg )
        return;

    // If found at least one curve with a small segment or with a loop,
    // allocate an array with all curves, removing found loops in each curve.
    size_t* curveSizesArray = (size_t*)malloc( (getNumberOfCurves()+1) * sizeof(size_t) );
    Point3D** curvesArray = (Point3D**)malloc( 
                                           (getNumberOfCurves()+1)*sizeof(Point3D*));
  curvesArray[0]=NULL;

    size_t i=1;
    for(currCurve = getFrstCurve(); 
        currCurve!=NULL; 
        currCurve = getNextCurve() )
    {
        curvesArray[i] = (Point3D*)malloc(getCurveSize()*sizeof(Point3D));
        CheckCurveLoops( getCurveSize(), currCurve, &curveLength, &smallestSeg );
        if( smallestSeg/curveLength < smallestSegFactor )
            smallestSeg = curveLength * smallestSegFactor;
        FilterCurve( getCurveSize(), currCurve, smallestSeg,
                     &curveSizesArray[i], curvesArray[i] );
        i++;
    }

    // Reallocates global curves array
    m_CurveArraySize=0;
    for(size_t i=1; i <= getNumberOfCurves(); i++ )
    {
        m_CurvesSizesArray[i] = curveSizesArray[i];
        m_CurveArraySize += m_CurvesSizesArray[i];
    }

    free(m_CurvePointsArray);
    m_CurvePointsArray = (Point3D*) malloc(m_CurveArraySize*sizeof(Point3D));
    m_CurveArrayIndex=0;
    for( size_t i=1; i <= getNumberOfCurves(); i++ )
    {
        for( size_t j=0; j < m_CurvesSizesArray[i]; j++ )
        {
            m_CurvePointsArray[m_CurveArrayIndex++] = curvesArray[i][j];
        }
    }

    // Release auxiliary memory
    for( size_t i=1; i <= getNumberOfCurves(); i++ )
  {
        free(curvesArray[i]);
    curvesArray[i]=NULL;
  }
    free(curvesArray);
  curvesArray=NULL;
    free(curveSizesArray);   
    curveSizesArray = NULL;
}
////////////////////////////////////////////////////////////////////
bool 
GenExactCurve::CheckCurveLoops(size_t curveSize, Point3D* curve,
                               double* curveLength, double* smallestSeg)
// Checks for zip-zag parts of given current curve.
// Also returns the total curve length and smallest segment size.
{ 
    bool found_loop = false;
    double pt[3];
    Point3D pt_prev;
    Point3D pt_curr;
    Point3D pt_next;
    Point3D seg_curr;
    Point3D seg_next;
    double  seg_next_len;
    double cos175 = -0.9962;

    curve[0].getXYZ(pt);
    pt_prev.setXYZ(pt);
    curve[1].getXYZ(pt);
    pt_curr.setXYZ(pt);
    seg_curr = pt_curr - pt_prev;
    *curveLength = *smallestSeg = seg_curr.len();
    for( size_t i=2; i<curveSize-1; i++ )
    {
        curve[i].getXYZ(pt);
        pt_next.setXYZ(pt);
        seg_next = pt_next - pt_curr;
        seg_next_len = seg_next.len();
        *curveLength += seg_next_len;
        if( seg_next_len < *smallestSeg )
            *smallestSeg = seg_next_len;
        if( seg_curr.dotProd(seg_next) > cos175 )
        {
            pt_prev = pt_curr;
            pt_curr = pt_next;
            seg_curr = pt_curr - pt_prev;
        }
        else
        {
            found_loop = true;
        }
    }
    curve[curveSize-2].getXYZ(pt);
    pt_curr.setXYZ(pt);
    curve[curveSize-1].getXYZ(pt);
    pt_next.setXYZ(pt);
    seg_next = pt_next - pt_curr;
    seg_next_len = seg_next.len();
    *curveLength += seg_next_len;
    if( seg_next_len < *smallestSeg )
        *smallestSeg = seg_next_len;

    return found_loop;
}
////////////////////////////////////////////////////////////////////
void 
GenExactCurve::FilterCurve(size_t curveSize, Point3D* curve, double smallestSeg, 
                           size_t* cleanCurveSize, Point3D* cleanCurve)
// Filter small segments and removes zip-zag parts of given current curve,
// stores the cleaned curve in given cleanCurve array and returns its new size.
{
    // The trivial case is when given curve has only one segment.
    // In this case just store the two curve points in the clean curve.
    if( curveSize == 2 )
    {
        *cleanCurveSize = 2;
        cleanCurve[0] = curve[0];
        cleanCurve[1] = curve[1];
        return;
    }

    // Local variables
    size_t second_index;
    size_t cleanCurveIndex;
    double pt[3];
    Point3D pt_prev;
    Point3D pt_curr;
    Point3D pt_next;
    Point3D seg_curr;
    Point3D seg_next;
    double  seg_next_len;
    double cos175 = -0.9962;

    // Get the first segment of clean curve.  It is assumed that there is no
    // zig-zag until found valid second point, i.e., look for a second
    // curve point that form with the first curve point a segment that is
    // greater than or equal the given smallest segment size.
    cleanCurve[0] = curve[0];
    curve[0].getXYZ(pt);
    pt_prev.setXYZ(pt);
    for( second_index=1; second_index<curveSize-1; second_index++ )
    {
        curve[second_index].getXYZ(pt);
        pt_curr.setXYZ(pt);
        seg_curr = pt_curr - pt_prev;
        if( seg_curr.len() >= smallestSeg )
        {
            break;
        }
    }

    // If the found second index of the clean curve is the antepenultimate
    // index of given curve, the resulting clean curve will either have 
    // two or three points, depending on the size of the last segment:
    // If it is smaller than the given smallest size, the clean curve will
    // have only two points.  Otherwise, it will have three points.
    if( second_index == curveSize-2 )
    {
        curve[curveSize-1].getXYZ(pt);
        pt_next.setXYZ(pt);
        seg_next = pt_next - pt_curr;
        if( seg_next.len() < smallestSeg )
        {
            *cleanCurveSize = 2;
            cleanCurve[1] = curve[curveSize-1];
        }
        else
        {
            *cleanCurveSize = 3;
            cleanCurve[1] = curve[curveSize-2];
            cleanCurve[2] = curve[curveSize-1];
        }
        return;
    }

    // Now handle the general case.  Traverse the curve segments, starting at
    // the second segment, check for small segments or zig-zig segments.
    curve[second_index].getXYZ(pt);
    pt_curr.setXYZ(pt);
    seg_curr = pt_curr - pt_prev;
    cleanCurve[1] = curve[second_index];
    cleanCurveIndex=2;
    for( size_t i=second_index+1; i<curveSize-1; i++ )
    {
        curve[i].getXYZ(pt);
        pt_next.setXYZ(pt);
        seg_next = pt_next - pt_curr;
        seg_next_len = seg_next.len();
        if((seg_next_len >= smallestSeg)&&(seg_curr.dotProd(seg_next) > cos175))


        {
            cleanCurve[cleanCurveIndex++] = curve[i];
            pt_prev = pt_curr;
            pt_curr = pt_next;
            seg_curr = pt_curr - pt_prev;
        }
#if SHOW_CURVE_CREATION // 1
        else if(seg_curr.dotProd(seg_next) <= cos175)
        {
            printf( "Found clean curve with zig-zag loop.\n" );
        }
#endif
    }

    // Finish up clean curve with the last given curve point.  However, 
    // assuming that there is no zig-zag with last segment, the antipenultimate
    // point of the given curve will only be considered if the size of the
    // last segment is greater than or equal the given smallest segment size.
    curve[curveSize-1].getXYZ(pt);
    pt_next.setXYZ(pt);
    seg_next = pt_next - pt_curr;
    if( seg_next.len() < smallestSeg )
    {
        cleanCurve[cleanCurveIndex-1] = curve[curveSize-1];
    }
    else
    {
        cleanCurve[cleanCurveIndex++] = curve[curveSize-1];
    }
    *cleanCurveSize = cleanCurveIndex;
}
////////////////////////////////////////////////////////////////////
void
GenExactCurve::StartInvertedSection()
{
#if SHOW_CURVE_CREATION
  printf("The next curve section is inverted!\n");
#endif

  // Curve section is inverted, with start index at CurveArrayIndex
  m_InvCrvStartIdxArray[m_CurvesNumber] = (int)m_CurveArrayIndex; 

}
////////////////////////////////////////////////////////////////////
void
GenExactCurve::EndInvertedSection()
{
  if(m_InvCrvStartIdxArray[m_CurvesNumber]<0)
    return;
  size_t InvCrvStartIndex = (size_t) m_InvCrvStartIdxArray[m_CurvesNumber];

  double temp[3];
  size_t InvCrvHalfSize = (m_CurveArrayIndex - InvCrvStartIndex)/2;
  for(size_t i=0; i<InvCrvHalfSize; i++)
  {
    m_CurvePointsArray[InvCrvStartIndex+i].getXYZ(temp);
    m_CurvePointsArray[InvCrvStartIndex+i].setXYZ(
      m_CurvePointsArray[m_CurveArrayIndex-1-i].getX(),
      m_CurvePointsArray[m_CurveArrayIndex-1-i].getY(),
      m_CurvePointsArray[m_CurveArrayIndex-1-i].getZ()  );
    m_CurvePointsArray[m_CurveArrayIndex-1-i].setXYZ(temp);
  }

#if SHOW_CURVE_CREATION
    printf("End of inverted Segment!\n");
#endif

}

#if 0

////////////////////////////////////////////////////////////////////
bool
GenExactCurve::AttactToVertex(  mgVtxTop* _vtx, 
                                Point3D* point    )
{
    return AttactToVertex(_vtx, point, m_tolerance);
}
//////////////////////////////////////////////////////////////////
bool
GenExactCurve::AttactToVertex( mgVtxTop* _vtx, 
                               Point3D* point, 
                               double _tolerance    )
{
    mgVertex* geovtx = (mgVertex*) _vtx->getGeom();
    Point3D p = geovtx->getCoord();
    double dist = point->distance( Point3D(p.getX(), p.getY(), p.getZ()) );
    if( dist < _tolerance   )
    {
        point->setX(p.getX());
        point->setY(p.getY());
        point->setZ(p.getZ());
#if SHOW_CURVE_CREATION //1
        printf("Attracted to Vertex:{%lf, %lf, %lf}, dist = %lf\n",
            point->getX(), point->getY(), point->getZ(), dist );
#endif
        return true;
    }

    return false;
}
//////////////////////////////////////////////////////////////////
bool
GenExactCurve::AttractToSegment(    mgSegment* _seg, 
                                    Point3D* point    )
{
    return AttractToSegment(_seg, point, m_tolerance);
}
//////////////////////////////////////////////////////////////////
bool 
GenExactCurve::AttractToSegment(    mgSegment* _seg, 
                                    Point3D* point, 
                                    double _tolerance   )
// Try to attract the given point to the given topological
// segment preferably, to a vertex of this segment. If it 
// was not possible, then try to attract to a kink of this 
// segment. Again, if it was not possible, try to attract
// to a point in the middle of this segment
{
    // Try to attract the given point to
    // the first vertex of this segment
    mgVtxTop* FrstVtx = (mgVtxTop*)_seg->getFrstVertex(); 
    if(AttactToVertex(FrstVtx, point, _tolerance))
        return true;

    // Try to attract the given point to
    // the last vertex of this segment
    mgVtxTop* LastVtx = (mgVtxTop*)_seg->getLastVertex();
    if(AttactToVertex(LastVtx, point, _tolerance))
        return true;

    // Get Equivalent Polyline of the topological segment
    mgCurve* geoCrv = (mgCurve*) _seg->getGeom();
    Curve* myCrv = geoCrv->getMyCurve();
    vector<Point3D> polypoints = myCrv->getPolygonalPoints();

    // Try to attract to a internal point with a kink
    // (angle between adjacent segments greater than 5 degrees).
    double cos5 = 0.9962;
    double min_dist = 1e+16;
    Point3D bestP;
    for(size_t i = 0; i < ((size_t) polypoints.size())-2; i++)
    {
        Point3D A = polypoints[i];
        Point3D B = polypoints[i+1];
        Point3D dirAB = B-A;
        dirAB.normalize();
        Point3D C = polypoints[i+2];
        Point3D dirBC = C-B;
        dirBC.normalize();
        double dist = point->distance(B);
        if(dirAB.dotProd(dirBC) <= cos5 )
        {
            if(dist < min_dist)
            {
                min_dist = dist;
                bestP = B;
            }
        }
    }

    if(min_dist <= _tolerance)
    {
        point->setX(bestP.getX());
        point->setY(bestP.getY());
        point->setZ(bestP.getZ());
#if SHOW_CURVE_CREATION// 1
        printf("Attracted to Kink:{%lf, %lf, %lf}, dist = %lf\n",
            point->getX(), point->getY(), point->getZ(), min_dist);
#endif
        return true;
    }


    // Try to attract to a point in the middle of the segment
    min_dist=1e+16;
    for( size_t i = 0; i < ((size_t) polypoints.size())-1; i++ )
    {    
        Point3D A = polypoints[i];
        Point3D B = *point;
        Point3D C = polypoints[i+1];

        if(A.distance2(C)==0.)
            continue;

        Point3D AB = B-A;
        Point3D ACn = C-A; ACn.normalize();
        double t = AB.dotProd(ACn);
        Point3D Pt = A + t*ACn;

        double dist = (B-Pt).len();
        if(dist<min_dist)
        {
            min_dist=dist;
            bestP=Pt;
        }
    }
    if(min_dist>_tolerance)
        return false;

    point->setX(bestP.getX());
    point->setY(bestP.getY());
    point->setZ(bestP.getZ());

#if SHOW_CURVE_CREATION //1
    printf("Attracted to Segment:{%lf, %lf, %lf}, dist = %lf\n",
        point->getX(), point->getY(), point->getZ(), min_dist);
#endif

    return true;
}
////////////////////////////////////////////////////////////////////
bool
GenExactCurve::AttractToTopology(   mgPatch2d* _p2d, 
                                    Point3D* point    )
{
    return AttractToTopology(_p2d, point, m_tolerance);
}
//////////////////////////////////////////////////////////////////
bool
GenExactCurve::AttractToTopology(   mgPatch2d* _patch2d, 
                                    Point3D* point, 
                                    double _tolerance   )
// Try to attract the given point to the topological entities
// associated to the given patch2d: its border curves, border
// vertexes, wires curves,wires vertexes, loops curves or 
// loops vertexes
{
    // Try to attract to the border curves of the patch
    mgSegment* seg = (mgSegment*) _patch2d->firstSegment();
    while(seg!=NULL)
    {
        if(AttractToSegment(seg, point, _tolerance))
            return true;
        seg = (mgSegment*) _patch2d->nextSegment();
    }

    // Try to attract to the wires of the patch
    mgSegment* wire = (mgSegment*) _patch2d->firstWire();
    while(wire!=NULL)
    {
        if(AttractToSegment(wire, point, _tolerance))
            return true;
        wire = (mgSegment*) _patch2d->nextWire();
    }

    // Try to attract to the loop curves of the patch
    mgPatch2d* loop = (mgPatch2d*) _patch2d->firstLoop();
    while(loop!=NULL)
    {
        mgSegment* loopseg = (mgSegment*) loop->firstSegment();
        while(loopseg!=NULL)
        {
            if(AttractToSegment(loopseg, point, _tolerance))
                return true;
            loopseg = (mgSegment*) loop->nextSegment();
        }
        loop = (mgPatch2d*) _patch2d->nextLoop();
    }

    return false;
}
#endif
//////////////////////////////////////////////////////////////////